from typing import List

from fastapi import APIRouter, HTTPException
from fastapi.templating import Jinja2Templates
from fastapi import Request
from pydantic import BaseModel, field_validator
from typing_extensions import ClassVar
from watchfiles import awatch

from models import Student, Course

router = APIRouter()

# 项目根路径针对的是启动文件所在的路径
templates = Jinja2Templates(directory="templates")



@router.get("/list", summary="学生列表")
async def get_list():
    # 1、查询所有
    # students = await Student.all()

    # 2、filter
    # students = await Student.filter(clas_id=4)
    # students = await Student.filter(clas_id__gte=4)  ## clas_id ≥ 4
    # students = await Student.filter(sno__in=[2023001, 2023002])  ## sno__in 精准查询
    # students = await Student.filter(sno__range=[1, 2023010])  ## sno__rang 范围

    # 3、get 返回一个对象

    # 4、模糊查询(不区分大小写加i)
    # students = await Student.filter(name__icontains="张")  ## name like %张%
    # students = await Student.filter(name__startswith ="张")  ## 	LIKE 'value%'
    # students = await Student.filter(name__iendswith ="张")  ## 	LIKE '%value'

    # for student in students:
    #     print(f"sno: {student.sno},name: {student.name},")

    # 5、values查询
    # students =await Student.all().values("sno","name")
    # for student in students:
    #     print(student["name"])

    # 3、get  单个对象

    # return {
    #     "查看所有的学生": students,
    # }

    # 一对多查询，多对多查询
    # 单个对象
    # info = await Student.get(name='张三')
    # print(await info.clas.values("name"))

    # 集合对象
    # students = await Student.all().values("name","clas__name")

    # 查询张三报的所有课程
    # print(await info.course.all().values("name","teacher__name"))

    # 查询学生集合的,班级名，课程名(因为查询的设计课程，不会返回集合，一个人选择多个课程，查询回来会有多条记录)
    students = await Student.all().values("name", "clas__name", "course__name")

    return students


@router.get("/index.html")
async def index(request: Request):
    # 查询数据时预加载关联
    students = await Student.all().prefetch_related("clas")
    return templates.TemplateResponse("index.html", {"request": request, "students": students})


@router.get("/get/{id}", response_model_exclude={"pwd"}, summary="学生详情")
async def get_info(stu_id: int):
    stu = await Student.get(id=stu_id)  # get是拿的一个对象
    return stu


class StudentIn(BaseModel):
    name: str
    pwd: str
    sno: int
    clas_id: int
    course_ids: List[int] = []  # 重命名为 course_ids 更明确

    @field_validator("name")
    def name_must_alpha(cls, value: str) -> str:  # 注意第一个参数是 cls（类方法）
        """验证 name 必须由字母组成"""
        assert len(value) > 2, 'name 长度不能小于2'
        return value

    @field_validator("sno")
    def sno_validate(cls, value: int) -> int:  # 注意第一个参数是 cls（类方法）
        """验证 name 必须由字母组成"""
        assert 2023001 <= value <= 2023100, '学号范围 2023001-2023100'
        return value


@router.post("/add", summary="新增学生", response_model_exclude={"pwd"})
async def add_student(student_in: StudentIn):
    # 传入到数据库
    # 1. 创建学生（排除 course_ids）
    student_data = student_in.model_dump(exclude={"course_ids"})
    student = await Student.create(**student_data)

    # 2. 添加课程关联（如果有）
    if student_in.course_ids:
        courses = await Course.filter(id__in=student_in.course_ids)
        await student.course.add(*courses)  # 添加多对多关系
    return student


@router.put("/update/{stu_id}", summary="更新学生")
async def update_student(stu_id: int, student_in: StudentIn):
    data = student_in.model_dump(exclude={"course_ids"})
    # 1. 修改学生（排除 course_ids）
    await Student.filter(id=stu_id).update(**data)

    # 2、设置课程
    edit_student = await Student.get(id=stu_id)
    if student_in.course_ids:
        courses = await Course.filter(id__in=student_in.course_ids)
        await edit_student.course.clear()
        await edit_student.course.add(*courses)  # 添加多对多关系

    return edit_student


@router.delete("/remove/{id}", summary="删除学生")
async def remove_student(id: int):
    delete_count = await Student.filter(id=id).delete()
    print(delete_count)
    #等价于 if delete_count == 0
    if not delete_count:
        raise HTTPException(status_code=404, detail=f"Student {id} not found")
    return {
        "message": "操作成功"
    }


